home *** CD-ROM | disk | FTP | other *** search
/ Magnum One / Magnum One (Mid-American Digital) (Disc Manufacturing).iso / d15 / infop141.arc / INFOPLUS.ASM < prev    next >
Assembly Source File  |  1990-12-07  |  31KB  |  993 lines

  1. ;--------------------------------------------------------------------
  2. ;
  3. ;       INFOPLUS.ASM
  4. ;
  5. ;       Version 1.41
  6. ;
  7. ;       Ten subprograms used by INFOPLUS.PAS:
  8. ;
  9. ;               CPUID           - identifies host CPU and NDP (if
  10. ;                                       any)
  11. ;               DISKREAD        - reads absolute sectors from disk
  12. ;               LONGCALL        - calls a routine using a CALL FAR
  13. ;               ATIINFO         - for accessing ATI VGAWonder cards
  14. ;               ALTINTR         - calls interrupts with a true INT call
  15. ;               ALTMSDOS        - calls DOS with a true INT call
  16. ;               CIRRUSCK        - Cirrus VGA check
  17. ;               CTICK           - Chips & Technologies VGA check
  18. ;               TSENGCK         - Tseng VGA check
  19. ;               ZYMOSCK         - ZyMOS VGA check
  20. ;
  21. ;       Originally by:
  22. ;       Steve Grant
  23. ;       Long Beach, CA
  24. ;       January 13, 1989
  25. ;
  26. ;       mods by Andrew Rossmann (12/8/90)
  27. ;--------------------------------------------------------------------
  28.  
  29. .286P
  30. .8087
  31.  
  32.         public  CPUID, DISKREAD, LONGCALL, ATIINFO, ALTINTR, ALTMSDOS
  33.         public  CTICK, TSENGCK, ZYMOSCK, CIRRUSCK
  34.  
  35. CODE    segment byte
  36.  
  37. ;       Conditional jumps are all coded with the SHORT qualifier in
  38. ;       order to minimize the size of the .OBJ file output of Turbo
  39. ;       Assembler.
  40.  
  41. ;--------------------------------------------------------------------
  42.  
  43. CPUID   proc    far
  44.  
  45. assume  cs:CODE, ds:DATA, es:nothing, ss:nothing
  46.  
  47. ;       On entry:
  48. ;
  49. ;               BP
  50. ;       SP =>   near return address
  51. ;               offset  of a cpu_info_t record
  52. ;               segment "  "     "        "
  53. ;       also, the test type byte should be a 'C' or 'N' to execute the
  54. ;       CPU or NDP tests.
  55. ;
  56. ;       On exit, the cpu_info_t record has been filled in as follows:
  57. ;
  58. ;               byte    = CPU type
  59. ;               word    = Machine Status Word
  60. ;               6 bytes = Global Descriptor Table
  61. ;               6 bytes = Interrupt Descriptor Table
  62. ;               boolean = segment register change/interrupt flag
  63. ;               byte    = NDP type
  64. ;               word    = NDP control word
  65. ;               byte    = Weitek presence
  66. ;               byte    = test type (C, N, or W)
  67.  
  68. cpu_info        equ     [bp + 6]
  69.  
  70. mCPU    equ     byte ptr [bx]
  71. mMSW    equ     word ptr [bx + 1]
  72. mGDT    equ     [bx + 3]
  73. mIDT    equ     [bx + 9]
  74. mchkint equ     byte ptr [bx + 15]
  75. mNDP    equ     byte ptr [bx + 16]
  76. mNDPCW  equ     word ptr [bx + 17]
  77. mWeitek equ     byte ptr [bx + 19]
  78. mtest   equ     byte ptr [bx + 20]
  79.  
  80. f8088   equ     0
  81. f8086   equ     1
  82. fV20    equ     2
  83. fV30    equ     3
  84. f80188  equ     4
  85. f80186  equ     5
  86. f80286  equ     6
  87. f80386  equ     7
  88. f80486  equ     8
  89. funk    =       0FFH
  90.  
  91. false   equ     0
  92. true    equ     1
  93.  
  94.         push    bp
  95.         mov     bp,sp
  96.         push    ds
  97.         lds     bx,cpu_info
  98.         cmp     mtest, 'C'
  99.         jnz     skipcpu
  100.         call    cpu
  101.         call    chkint
  102. skipcpu:
  103.         cmp     mtest, 'N'
  104.         jnz     skipndp
  105.         call    ndp
  106. skipndp:
  107.         cmp     mtest, 'W'
  108.         jnz     skipweitek
  109.         call    weitek
  110. skipweitek:
  111.         pop     ds
  112.         pop     bp
  113.         ret     4
  114. CPUID   endp
  115.  
  116. ;--------------------------------------------------------------------
  117.  
  118. cpu     proc    near
  119.  
  120. ; interrupt of multi-prefix string instruction
  121.  
  122.         mov     mCPU,funk               ;set CPU type to unknown
  123.         sti
  124.         mov     cx,0FFFFH
  125. rep     lods    byte ptr es:[si]
  126.         jcxz    short cpu_02
  127.         call    piq
  128.         cmp     dx,4
  129.         jg      short cpu_01
  130.         mov     mCPU,f8088
  131.         jmp     cpu_done
  132. cpu_01:
  133.         cmp     dx,6
  134.         jne     cpu_01a
  135.         mov     mCPU,f8086
  136. cpu_01a:
  137.         jmp     cpu_done
  138. cpu_02:
  139.  
  140. ; number of bits in displacement register used by shift
  141.  
  142.         mov     al,0FFH
  143.         mov     cl,20H
  144.         shl     al,cl
  145.         or      al,al
  146.         jnz     short cpu_04
  147.         call    piq
  148.         cmp     dx,4
  149.         jg      short cpu_03
  150.         mov     mCPU,fV20
  151.         jmp     cpu_done
  152. cpu_03:
  153.         cmp     dx,6
  154.         je      cpu_03a
  155.         jmp     cpu_done
  156. cpu_03a:
  157.         mov     mCPU,fV30
  158.         jmp     cpu_done
  159. cpu_04:
  160.  
  161. ; order of write/decrement by PUSH SP
  162.  
  163.         push    sp
  164.         pop     ax
  165.         cmp     ax,sp
  166.         je      short cpu_06
  167.         call    piq
  168.         cmp     dx,4
  169.         jg      short cpu_05
  170.         mov     mCPU,f80188
  171.         jmp     cpu_done
  172. cpu_05:
  173.         cmp     dx,6
  174.         jne     short cpu_done
  175.         mov     mCPU,f80186
  176.         jmp     cpu_done
  177.  
  178. ; We most likely have a 286, 386 or 486 CPU by now
  179. ;First, grab some tables
  180.  
  181. cpu_06:
  182.         smsw    mMSW
  183.         sgdt    mGDT
  184.         sidt    mIDT
  185.  
  186. ;!!!!!!!
  187. ;!!! Original 286/386 detection code (modified 8/10/90)
  188. ;!!! Modified by code supplied by John Levine, apparantly from an Intel
  189. ;!!! '486 manual.
  190. ;!!!!!!!
  191.  
  192.         pushf                           ;put flags into CX
  193.         pop     cx
  194.         and     cx,0fffh                ;mask off upper 4 bits
  195.         push    cx
  196.         popf
  197.         pushf
  198.         pop     ax
  199.         and     ax,0f000h               ;look only at upper 4 bits
  200.         cmp     ax,0f000h               ;88/86 etc.. turn them on
  201.         jz      badcpu                  ;not 286/386/486!!!
  202.         or      cx,0f000h               ;force upper 4 bits on
  203.         push    cx
  204.         popf
  205.         pushf
  206.         pop     ax
  207.         and     ax,0f000h
  208.         jz      found286                ;bits are zeroed in real mode 286
  209. ;
  210. ;since we probably have have a 386 or 486 by now, we need to do some 32-bit
  211. ;work. Detect the 486 by seeing if the Alignment Check flag is settable. This
  212. ;flag only exists on the '486.
  213. ;
  214. .386
  215.         and     esp,0FFFFh              ;use only 64K stack
  216.         mov     edx,esp                 ;save current stack position
  217.         and     esp,0FFFCh              ;dword align to avoid traps
  218.         pushfd                          ;push 32 bit flag
  219.         pop     eax
  220.         mov     ecx,eax                 ;save current flags
  221.         xor     eax,40000h              ;flip AC (alignment check) flag
  222.         push    eax
  223.         popfd
  224.         pushfd
  225.         pop     eax
  226.         xor     eax,ecx                 ;eliminate all but AC bit
  227.         push    ecx                     ;restore flags
  228.         popfd
  229.         mov     esp,edx                 ;restore stack position
  230.         test    eax,40000h              ;is bit set?
  231. .286
  232.         jz      found386                ;if not, is a 386
  233.         mov     mCPU,f80486             ;must be a 486!!
  234.         jmp     short cpu_done
  235. found286:
  236.         mov     mCPU,f80286
  237.         jmp     short cpu_done
  238. found386:
  239.         mov     mCPU,f80386
  240.         jmp     short cpu_done
  241. badcpu:
  242.         mov     mCPU,funk               ;how'd an 8088 get this far?????
  243. CPU_done:
  244.         ret
  245. cpu     endp
  246. ;--------------------------------------------------------------------
  247.  
  248. piq     proc    near
  249.  
  250. ;       On exit:
  251. ;
  252. ;               DX      = length of prefetch instruction queue
  253. ;
  254. ;       This subroutine uses self-modifying code, but can
  255. ;       nevertheless be run repeatedly in the course of the calling
  256. ;       program.
  257.  
  258. count   =       7
  259. opincdx equ     42H                     ; inc dx opcode
  260. opnop   equ     90H                     ; nop opcode
  261.  
  262.         mov     al,opincdx
  263.         mov     cx,count
  264.         push    cx
  265.         push    cs
  266.         pop     es
  267.         mov     di,offset piq_01 - 1
  268.         push    di
  269.         std
  270.         rep stosb
  271.         mov     al,opnop
  272.         pop     di
  273.         pop     cx
  274.         xor     dx,dx
  275.         cli
  276.         rep stosb
  277.         rept    count
  278.         inc     dx
  279.         endm
  280. piq_01:
  281.         sti
  282.         ret
  283. piq     endp
  284.  
  285. ;--------------------------------------------------------------------
  286.  
  287. chkint  proc    near
  288.  
  289. ; save old INT 01H vector
  290.  
  291.         push    bx
  292.         mov     ax,3501H
  293.         int     21H
  294.         mov     old_int01_ofs,bx
  295.         mov     old_int01_seg,es
  296.         pop     bx
  297.  
  298. ; redirect INT 01H vector
  299.  
  300.         push    ds
  301.         mov     ax,2501H
  302.         mov     dx,seg new_int01
  303.         mov     ds,dx
  304.         mov     dx,offset new_int01
  305.         int     21H
  306.         pop     ds
  307.  
  308. ; set TF and change SS -- did we trap on following instruction?
  309.  
  310.         pushf
  311.         pop     ax
  312.         or      ah,01H                  ; set TF
  313.         push    ax
  314.         popf
  315.         push    ss                      ; CPU may wait one
  316.                                         ; instruction before
  317.                                         ; recognizing single step
  318.                                         ; interrupt
  319.         pop     ss
  320. chkint_01:                              ; shouldn't ever trap here
  321.  
  322. ; restore old INT 01H vector
  323.  
  324.         push    ds
  325.         mov     ax,2501H
  326.         lds     dx,old_int01
  327.         int     21H
  328.         pop     ds
  329.         ret
  330. chkint  endp
  331. ;--------------------------------------------------------------------
  332.  
  333. new_int01       proc    near
  334.  
  335. ;       INT 01H handler (single step)
  336. ;
  337. ;       On entry:
  338. ;
  339. ;       SP =>   IP
  340. ;               CS
  341. ;               flags
  342.  
  343.         sti
  344.         pop     ax                      ; IP
  345.         cmp     ax,offset chkint_01
  346.         jb      short new_int01_03
  347.         je      short new_int01_01
  348.         mov     mchkint,false
  349.         jmp     short new_int01_02
  350. new_int01_01:
  351.         mov     mchkint,true
  352. new_int01_02:
  353.         pop     cx                      ; CS
  354.         pop     dx                      ; flags
  355.         and     dh,0FEH                 ; turn off TF
  356.         push    dx                      ; flags
  357.         push    cx                      ; CS
  358. new_int01_03:
  359.         push    ax                      ; IP
  360.         iret
  361. new_int01       endp
  362. ;--------------------------------------------------------------------
  363.  
  364. ndp     proc    near
  365.  
  366. fnone   equ     0
  367. f8087   equ     1
  368. f80287  equ     2
  369. f80387  equ     3
  370. funk    =       0FFH
  371.  
  372.  
  373. ; The next two 80x87 instructions cannot carry the WAIT prefix,
  374. ; because there may not be an 80x87 for which to wait.  The WAIT is
  375. ; therefore emulated with a MOV CX,<value>! LOOP $ combination.
  376.  
  377. .287
  378.         mov     word ptr ndp_cw,0000H
  379.         cli                     ;no interrupts during this test
  380.  
  381.         fninit                  ;initialize NDP
  382.         mov     cx,2
  383.         loop    $
  384.  
  385.         fnstcw  ndp_cw          ;store control word in ndp_cw
  386.         mov     cx,14h
  387.         loop    $
  388.  
  389.         sti
  390.         mov     ax,ndp_cw       ;check for valid status word
  391.         cmp     ah,3            ;is NDP present?
  392.         je      short ndp_01    ;if 3, must be there
  393.         mov     mNDP,fnone
  394.         jmp     short ndp_done
  395.  
  396. ndp_01:
  397.         cmp     ax,03FFH        ;check if 8087
  398.         jne     short ndp_02
  399.         mov     mNDP,f8087
  400.         jmp     short ndp_04
  401. ndp_02:
  402.  
  403. .287
  404.  
  405.         cmp     ax,037FH        ;check if 286/387/486
  406.         jne     short ndp_05    ;must be garbage
  407.  
  408. ;detect 287 or 387
  409.  
  410.         fld1                    ;Load +1.0 onto NDP stack
  411.         fldz                    ;Load +0.0 onto NDP stack
  412.         fdiv                    ;do +1/0
  413.         fld1                    ;Load +1.0 onto NDP stack
  414.         fchs                    ;Change to -1.0
  415.         fldz                    ;Load +0.0 onto NDP stack
  416.         fdiv                    ;do -1/0
  417.         fcom                    ;compare
  418.         fstsw   ndp_sw
  419.         mov     ax,ndp_sw
  420.         and     ah,41H          ; C3, C0
  421.         cmp     ah,40H          ; ST(0) = ST(1)
  422.         jne     short ndp_03
  423.         mov     mNDP,f80287
  424.         jmp     short ndp_04
  425. ndp_03:
  426.         cmp     ah,01H          ; ST(0) < ST(1)
  427.         jne     short ndp_05
  428.         mov     mNDP,f80387
  429. ndp_04:
  430.  
  431. .8087
  432.         fstcw   mNDPCW          ;save status for INFOPLUS
  433.         ret
  434. ndp_05:
  435.         mov     mNDP,funk
  436. ndp_done:
  437.         ret
  438. ndp     endp
  439.  
  440. ;------------------------------------------------------------------------------
  441. ; This checks to see if the BIOS reports a Weitek math coprocessor. This should
  442. ; only be called if a 386 or 486 is found.
  443. ; NOTE!! This may not work with all computers!!
  444.  
  445. fnoWeitek       equ     0
  446. fWeitek         equ     1
  447. fWeitek_real    equ     81h
  448.  
  449. weitek  proc    near
  450. .386
  451.         xor     eax,eax                 ;zero everything
  452.         int     11h                     ;do equipment check
  453.         test    eax,01000000h           ;check bit 24, set if Weitek present
  454.         je      no_weitek
  455.         mov     mWeitek,fWeitek
  456.         test    eax,0800000h            ;check bit 23, set if Weitek can be
  457.         je      weitek_done             ; addressed in real mode
  458.         mov     mWeitek,fWeitek_real
  459.         jmp     short weitek_done
  460. no_weitek:
  461.         mov     mWeitek,fnoWeitek
  462. weitek_done:
  463.         ret
  464. .286
  465. weitek  endp
  466.  
  467. ;--------------------------------------------------------------------
  468.  
  469. DISKREAD        proc    far
  470.  
  471. assume cs:CODE, ds:DATA, es:nothing
  472.  
  473. ;       On entry:
  474. ;
  475. ;               BP
  476. ;       SP =>   near return address
  477. ;               offset  of disk buffer
  478. ;               segment "   "     "
  479. ;               number of sectors to read
  480. ;               starting logical sector number
  481. ;               drive number (0=A, 1=B, etc.)
  482. ;
  483. ;       On exit:
  484. ;
  485. ;               AX      = function result
  486. ;                       00      - function successful
  487. ;                       01..FF  - DOS INT 25H error result
  488.  
  489.         drive                   equ     [bp + 16]
  490.         starting_sector         equ     [bp + 12]
  491.         number_of_sectors       equ     [bp + 10]
  492.         buffer                  equ     [bp + 6]
  493.  
  494.         push    bp
  495.         mov     bp,sp
  496.         mov     ax,3000h                ;get DOS version
  497.         int     21h
  498.         cmp     al,4                    ;DOS 4?
  499.         jge     read4                   ;We have 4 or newer, so use extended
  500.         cmp     ax,1d04h                ;use old for anything less than 3.30
  501.         jle     read3
  502. ;
  503. ;Check bit 1 of the device attributes bit. If it's set, then the driver
  504. ;supports use of the extended access method
  505. ;
  506.         push    es                      ;save regs
  507.         push    ds
  508.         mov     dl,drive                ;get drive number (0=A,1=B,etc)
  509.         inc     dl                      ;func uses 0=dflt, 1=A, etc..
  510.         mov     ah,32h                  ;get driver parameter block
  511.         int     21h
  512.         push    ds                      ;move ds to es
  513.         pop     es
  514.         pop     ds                      ;restore original ds
  515.         les     bx,[es:bx + 12h]        ;point ES:BX to device driver
  516.         test    word ptr [es:bx + 4],2  ;test device attributes
  517.         pop     es
  518.         jz      read3                   ;wasn't, so use old method
  519.  
  520. read4:
  521.         mov     al,drive
  522.         mov     bx,starting_sector      ;copy info into parameter block
  523.         mov     extd_starting_sector_lo,bx
  524.         mov     bx,starting_sector + 2
  525.         mov     extd_starting_sector_hi,bx
  526.         mov     bx,number_of_sectors
  527.         mov     extd_number_of_sectors,bx
  528.         les     bx,buffer               ;get seg:ofs of buffer in ES:BX
  529.         mov     extd_bufofs,bx          ;put into block
  530.         mov     extd_bufseg,es
  531.         mov     bx,offset dos4_block    ;DS:BX points to block
  532.         mov     cx,-1                   ;-1 means extended read
  533.         push    ds                      ;save DS (not really needed, but lets
  534.                                         ;me share code with DOS 3 read.)
  535.         jmp     short readit
  536.  
  537. read3:  mov     al,drive
  538.         mov     dx,starting_sector
  539.         mov     cx,number_of_sectors
  540.         push    ds
  541.         lds     bx,buffer               ;get seg:ofs of buffer in DS:BX
  542. readit: int     25H
  543.         inc     sp                      ; fix broken stack
  544.         inc     sp
  545.         pop     ds
  546.         jc      short diskread_01
  547.         xor     ax,ax
  548. diskread_01:
  549.  
  550.         pop     bp
  551.         ret     10
  552.  
  553. DISKREAD        endp
  554.  
  555. ;
  556. ;LONGCALL will call a routine using a CALL FAR.
  557. ;
  558. ;Pascal format: procedure longcall(addr: longint; var regs: registers); external;
  559. ;
  560.  
  561. longcall        proc    far
  562.         assume  cs:CODE, ds:DATA, es:nothing
  563.  
  564. regaddr equ     [bp + 6]
  565. addr    equ     [bp + 10]
  566.  
  567.         push    bp
  568.         mov     bp,sp
  569.         push    ds
  570.         mov     ax,addr                 ;copy calling address for later use
  571.         mov     word ptr cs:address,ax
  572.         mov     ax,addr+2
  573.         mov     word ptr cs:address+2,ax
  574.         lds     si,regaddr              ;get pointer to regs
  575.         mov     cs:ds_save,ds           ;save needed ones
  576.         mov     cs:si_save,si
  577.         cld                             ;go forward
  578.         lodsw                           ;load AX and hold it
  579.         push    ax
  580.         lodsw                           ;load BX
  581.         mov     bx,ax
  582.         lodsw                           ;load CX
  583.         mov     cx,ax
  584.         lodsw                           ;load DX
  585.         mov     dx,ax
  586.         lodsw                           ;load BP
  587.         mov     bp,ax
  588.         lodsw                           ;load SI and hold it
  589.         push    ax
  590.         lodsw                           ;load DI
  591.         mov     di,ax
  592.         lodsw                           ;load DS and hold it
  593.         push    ax
  594.         lodsw                           ;load ES
  595.         mov     es,ax
  596.         lodsw                           ;load Flags
  597.         push    ax
  598.         popf
  599.         pop     ds                      ;get rest of regs
  600.         pop     si
  601.         pop     ax
  602.         call    dword ptr cs:address    ;make far call
  603.         pushf                           ;save flags and modified regs
  604.         push    es
  605.         push    di
  606.         mov     es,cs:save_ds           ;get regs pointer into ES:DI
  607.         mov     di,cs:save_si
  608.         cld                             ;go forward
  609.         stosw                           ;save AX
  610.         mov     ax,bx
  611.         stosw                           ;save BX
  612.         mov     ax,cx
  613.         stosw                           ;save CX
  614.         mov     ax,dx
  615.         stosw                           ;save DX
  616.         mov     ax,bp
  617.         stosw                           ;save BP
  618.         mov     ax,si
  619.         stosw                           ;save SI
  620.         pop     ax
  621.         stosw                           ;save DI
  622.         mov     ax,ds
  623.         stosw                           ;save DS
  624.         pop     ax
  625.         stosw                           ;save ES
  626.         pop     ax
  627.         stosw                           ;save Flags
  628.         pop     ds                      ;restore regs
  629.         pop     bp
  630.         ret     8
  631.  
  632. address dd      ?
  633. ds_save dw      ?
  634. si_save dw      ?
  635.  
  636. longcall endp
  637.  
  638. ;
  639. ; ATIINFO is used in the Video identification routine to get special
  640. ; information from ATI VGA Wonder cards.
  641. ;
  642. ; Pascal format: function ATIinfo(data_in: byte; register: word): byte;
  643. ;
  644. ATIinfo         proc    far
  645.         assume  cs:CODE, ds:DATA, es:NOTHING
  646.  
  647. data_in         equ     [bp+8]
  648. register        equ     [bp+6]
  649.  
  650.         push    bp
  651.         mov     bp,sp
  652.         mov     dx,register             ;get register
  653.         mov     ax,data_in              ;get command word (actually byte)
  654.         cli                             ;no interrupts
  655.         out     dx,al
  656.         inc     dx                      ;next port
  657.         in      al,dx                   ;get result
  658.         sti                             ;restore interrupts
  659.         mov     sp,bp
  660.         pop     bp
  661.         ret     4
  662.  
  663. ATIinfo endp
  664.  
  665. ; AltIntr is an alternative to the Intr function. The standard Intr function
  666. ; does not do a true Interrupt!! Instead, it gets the address of the interrupt
  667. ; from the interrupt table, loads all the registers, and then does a RETF!!!
  668. ; The address of a return routine has been pushed on the stack so that it
  669. ; returns to TP and unloads the registers. This was probably done because
  670. ; Intel saw to it that all interrupt numbers must be immediate, and Borland
  671. ; didn't want to use self-modifying code.
  672. ;   NOTE: The MsDos routine is ALSO affected by this problem. It just stuffs
  673. ; a 21h into the stack, and calls Intr!!! So you can use ALTMSDOS instead!
  674. ;   Now, normally, the above procedure works perfectly fine, except under 1
  675. ; condition. When the CPU is under protected or Virtual 86 mode. When in those
  676. ; modes, a program with higher privileges can trap an interrupt and act on it.
  677. ; I found this out the hard way by going nuts wondering why I couldn't detect
  678. ; DPMI drivers or Windows!! My alternative Interrupt functions identically to
  679. ; Borlands, but uses self-modifying code to generate a true interrupt. To
  680. ; prevent possible problems with CPU pipelining, the entry point is near the
  681. ; end of the code, and then jumps back to continue.
  682. ;
  683. ; Pascal format: procedure AltIntr(intno: byte; regs: registers); external;
  684.  
  685. ALTINTRP        proc    far
  686.         assume  cs:CODE, ds:DATA, es:NOTHING
  687.  
  688. regaddr equ     [bp + 6]
  689. intno   equ     [bp + 10]
  690.  
  691.  
  692. altcont:
  693.         lds     si,regaddr              ;point DS:SI to regs
  694.         mov     cs:save_ds,ds           ;save pointer for return
  695.         mov     cs:save_si,si
  696.         cld                             ;go forward
  697.         lodsw                           ;load AX and hold it
  698.         push    ax
  699.         lodsw                           ;load BX
  700.         mov     bx,ax
  701.         lodsw                           ;load CX
  702.         mov     cx,ax
  703.         lodsw                           ;load DX
  704.         mov     dx,ax
  705.         lodsw                           ;load BP
  706.         mov     bp,ax
  707.         lodsw                           ;load SI and hold it
  708.         push    ax
  709.         lodsw                           ;load DI
  710.         mov     di,ax
  711.         lodsw                           ;load DS and hold it
  712.         push    ax
  713.         lodsw                           ;load ES
  714.         mov     es,ax
  715.         lodsw                           ;load Flags
  716.         push    ax
  717.         popf
  718.         pop     ds                      ;get rest of regs
  719.         pop     si
  720.         pop     ax
  721.         db      0cdh                    ;Int opcode
  722. intrpt  db      ?                       ;loaded with real interrupt
  723.         pushf                           ;save flags and modified regs
  724.         push    es
  725.         push    di
  726.         mov     es,cs:save_ds           ;get regs pointer into ES:DI
  727.         mov     di,cs:save_si
  728.         cld                             ;go forward
  729.         stosw                           ;save AX
  730.         mov     ax,bx
  731.         stosw                           ;save BX
  732.         mov     ax,cx
  733.         stosw                           ;save CX
  734.         mov     ax,dx
  735.         stosw                           ;save DX
  736.         mov     ax,bp
  737.         stosw                           ;save BP
  738.         mov     ax,si
  739.         stosw                           ;save SI
  740.         pop     ax
  741.         stosw                           ;save DI
  742.         mov     ax,ds
  743.         stosw                           ;save DS
  744.         pop     ax
  745.         stosw                           ;save ES
  746.         pop     ax
  747.         stosw                           ;save Flags
  748.         pop     ds                      ;restore regs
  749.         pop     bp
  750.         ret     6
  751.  
  752. altintr:
  753.         push    bp
  754.         mov     bp,sp
  755.         push    ds                      ;save DS, because we screw it up
  756.         mov     al,intno                ;get interrupt number to use
  757.         mov     cs:intrpt,al            ;and modify our code
  758.         jmp     altcont                 ;continue with rest of code
  759.  
  760. ;local storage
  761.  
  762. save_ds dw      ?
  763. save_si dw      ?
  764.  
  765. ALTINTRP        endp
  766. ;
  767. ; Pascal format: procedure AltMsDos(var regs: registers); external;
  768. ;
  769. ALTMSDOS        proc    far
  770.         assume  cs:CODE, ds:DATA, es:NOTHING
  771.  
  772.         pop     si              ;back track a bit so we can stuff
  773.         pop     dx              ;interrupt number in
  774.         pop     cx
  775.         pop     bx
  776.         mov     al,21h          ;push interrupt number
  777.         push    ax
  778.         push    bx
  779.         push    cx              ;restore other info
  780.         push    dx
  781.         push    si
  782.         jmp     ALTINTR         ;do interrupt call
  783.  
  784. ALTMSDOS        endp
  785.  
  786. CIRRUSCK        proc    far
  787.         assume  cs:CODE, ds:DATA, es:nothing;
  788.  
  789. ;Cirrus VGA detection from 'Advanced Programmer's Guide to Super VGAs'
  790.  
  791. ; Fetch address of CRT controller
  792.         mov     ax,40h          ;BIOS segment
  793.         mov     es,ax
  794.         mov     dx,es:[63h]     ;get CRTC address
  795.         push    dx              ;save
  796. ; clear Start Address register in CRTC (index 0Ch)
  797.         mov     al,0ch          ;index of Start Address reg
  798.         out     dx,al           ;select
  799.         inc     dx
  800.         in      al,dx           ;get current value
  801.         mov     ah,al           ;save
  802.         mov     al,0ch
  803.         push    ax
  804.         xor     al,al
  805.         out     dx,al           ;clear start address reg
  806.         dec     dx
  807. ; fetch unlock password
  808.         mov     al,1fh
  809.         out     dx,al           ;select id reg
  810.         inc     dx
  811.         in      al,dx           ;read unlock password
  812.         mov     ah,al           ;save
  813. ; enable extended regs
  814.         mov     dx,3c4h         ;address of sequencer
  815.         mov     al,6
  816.         out     dx,al           ;select extension control reg
  817.         inc     dx
  818.         mov     al,ah           ;get unlock password
  819.         out     dx,al           ;enable extended regs
  820.         in      al,dx           ;read back extension reg
  821.         cmp     al,1
  822.         jne     not_cirrus      ;wasn't a cirrus
  823. ;disable extended regs
  824.         mov     al,ah           ;get unlock password
  825.         ror     al,1            ;compute lock password
  826.         ror     al,1
  827.         ror     al,1
  828.         ror     al,1
  829.         out     dx,al           ;lock extended regs
  830.         in      al,dx           ;read extended control reg
  831.         cmp     al,0            ;is it 0
  832.         jne     not_cirrus      ;wasn't cirrus
  833.         pop     ax              ;restore regs
  834.         pop     dx
  835.         dec     dx              ;restore register C
  836.         out     dx,al
  837.         inc     dx
  838.         mov     al,ah
  839.         out     dx,al
  840.         mov     ax,1
  841.         jmp     short end_cirrusck
  842. not_cirrus:
  843.         pop     ax              ;restore regs
  844.         pop     dx
  845.         dec     dx
  846.         out     dx,al
  847.         inc     dx
  848.         mov     al,ah
  849.         out     dx,al           ;restore registerC
  850.         xor     ax,ax
  851. end_cirrusck:
  852.         ret
  853.  
  854. CIRRUSCK        endp
  855.  
  856. CTICK   proc    far
  857.         assume  cs:CODE, ds:DATA, es:nothing;
  858.  
  859. ;CTI VGA detection from 'Advanced Programmer's Guide to Super VGAs'
  860.  
  861. ;place VGA in setup mode
  862.         cli
  863.         mov     dx,46e8h        ;address of setup control reg
  864.         in      al,dx
  865.         or      al,10h          ;turn on setup bit
  866.         out     dx,al           ;go to setup mode
  867. ;enable extended register bank
  868.         mov     dx,103h         ;extended reg address
  869.         in      al,dx
  870.         or      al,80h          ;turn enable bit on
  871.         out     dx,al
  872. ;read global ID
  873.         mov     dx,104h         ;global ID reg
  874.         in      al,dx
  875.         mov     ah,al           ;save
  876. ; place vga in normal mode
  877.         mov     dx,46e8h
  878.         in      al,dx
  879.         and     al,03fh
  880.         out     dx,al
  881.         sti
  882. ; read version extended register
  883.         mov     dx,3d6h
  884.         mov     al,0
  885.         out     dx,al           ;select version register
  886.         inc     dx
  887.         in      al,dx
  888.         cmp     ah,5ah          ;check for CTI ID
  889.         jne     notcti
  890.         and     al,0f0h         ;adjust chip id
  891.         shr     al,1
  892.         shr     al,1
  893.         shr     al,1
  894.         shr     al,1
  895.         cmp     al,2            ;only 0, 1 and 3 are good
  896.         je      notcti
  897.         cmp     al,4
  898.         jge     notcti
  899.         cmp     al,3
  900.         je      end_ctick
  901.         inc     al              ;adjust to match chip number
  902.         jmp     short end_ctick
  903. notcti:
  904.         xor     ax,ax
  905. end_ctick:
  906.         ret
  907.  
  908. CTICK   endp
  909.  
  910. TSENGCK proc    far
  911.         assume  cs:CODE, ds:DATA, es:nothing;
  912.  
  913. ;Tseng VGA detection from 'Advanced Programmer's Guide to Super VGAs'
  914.  
  915.         mov     dx,3cdh         ;page select reg
  916.         in      al,dx
  917.         mov     ah,al           ;save
  918.         and     al,0c0h         ;save some bits
  919.         or      al,55h          ;test value one
  920.         out     dx,al           ;write it
  921.         in      al,dx
  922.         cmp     al,55h          ;same?
  923.         jne     nottseng
  924.         mov     al,0aah         ;test value two
  925.         out     dx,al
  926.         in      al,dx
  927.         cmp     al,0aah         ;same
  928.         jne     nottseng
  929.         mov     al,ah           ;restore original settings
  930.         out     dx,al
  931.         mov     al,1
  932.         jmp     short end_tsengck
  933. nottseng:
  934.         mov     al,0
  935. end_tsengck:
  936.         ret
  937.  
  938. TSENGCK endp
  939.  
  940. ZYMOSCK proc    far
  941.         assume  cs:CODE, ds:DATA, es:nothing;
  942.  
  943. ;ZyMOS VGA detection from 'Advanced Programmer's Guide to Super VGAs'
  944.  
  945.         mov     dx,3c4h         ;extended reg bank
  946.         mov     al,0bh          ;version reg
  947.         out     dx,al
  948.         inc     dx
  949.         in      al,dx           ;get version
  950.         and     al,0fh
  951.         cmp     al,2
  952.         je      end_zymosck
  953.         mov     al,0
  954. end_zymosck:
  955.         ret
  956. ZYMOSCK endp
  957.  
  958. code    ends
  959.  
  960. ;--------------------------------------------------------------------
  961.  
  962. DATA    segment byte
  963.  
  964. ; storage for CPUID
  965.  
  966. ; redirected INT 01H vector
  967.  
  968. old_int01       label   dword
  969. old_int01_ofs   dw      ?
  970. old_int01_seg   dw      ?
  971.  
  972. ; storage for NDPID
  973.  
  974. ; 80x87 control word after initialization, status word after divide by zero
  975.  
  976. ndp_cw          dw      ?
  977. ndp_sw          dw      ?
  978.  
  979. ; storage for DISKREAD
  980.  
  981. ; DOS 4.0 extended read parameter block
  982. dos4_block                      label   byte
  983. extd_starting_sector_lo         dw      ?
  984. extd_starting_sector_hi         dw      ?
  985. extd_number_of_sectors          dw      ?
  986. extd_bufofs                     dw      ?
  987. extd_bufseg                     dw      ?
  988.  
  989.  
  990. DATA    ends
  991.  
  992.         end
  993.